/*
 * Copyright (c) 2021 Futurewei Technologies, Inc.
 *
 * clang2mpl is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan
 * PSL v2. You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the
 * Mulan PSL v2 for more details.
 */
// RUN: %clang2mpl --ascii --verify %s -- -Wno-unused-value --target=aarch64-linux-elf
// RUN: cat %m | %FileCheck %s
void foo();
void bar(int);
int baz(int *, int);

int g;

struct A {
  int x;
  int y;
} gA1;

void call() {
  int x, y, *z;

  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: call &foo ()
  foo();
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: call &bar (constval i32 0)
  bar(0);
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: call &bar (dread i32 $g)
  bar(g);
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: call &baz (addrof a64 $g, constval i32 4)
  baz(&g, 4);
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: callassigned &baz (addrof a64 %x, dread i32 %y) { dassign %_result[[#RES1:]] 0 }
  // CHECK-NEXT: dassign %x 0 (dread i32 %_result[[#RES1]])
  x = baz(&x, y);
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: callassigned &baz (addrof a64 %x, dread i32 %y) { dassign %_result[[#RES2:]] 0 }
  // CHECK-NEXT: dassign $g 0 (dread i32 %_result[[#RES2]])
  g = baz(&x, y);
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: callassigned &baz (dread a64 %z, dread i32 %x) { dassign %_result[[#RES3:]] 0 }
  // CHECK-NEXT: iassign <* i32> 0 (dread a64 %z, dread i32 %_result[[#RES3]])
  *z = baz(z, x);
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: callassigned &baz (dread a64 %z, dread i32 %y) { dassign %_result[[#RES4:]] 0 }
  // CHECK-NEXT: eval (add i32 (dread i32 %x, dread i32 %_result[[#RES4]]))
  x + baz(z, y);
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: callassigned &baz (dread a64 %z, dread i32 %y) { dassign %_result[[#RES5:]] 0 }
  // CHECK-NEXT: dassign $gA1 2 (dread i32 %_result[[#RES5]])
  gA1.y = baz(z, y);
}

void icall(void (ifoo)(), void (ibar)(int), int (ibaz)(int *, int)) {
  int x, y, *z;

  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: icall (dread a64 %ifoo)
  ifoo();
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: icall (dread a64 %ibar, constval i32 0)
  ibar(0);
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: icall (dread a64 %ibar, dread i32 $g)
  ibar(g);
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: icall (dread a64 %ibaz, addrof a64 $g, constval i32 4)
  ibaz(&g, 4);
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: icallassigned (dread a64 %ibaz, addrof a64 %x, dread i32 %y) { dassign %_result[[#RES11:]] 0 }
  // CHECK-NEXT: dassign %x 0 (dread i32 %_result[[#RES11]])
  x = ibaz(&x, y);
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: icallassigned (dread a64 %ibaz, dread a64 %z, dread i32 %x) { dassign %_result[[#RES6:]] 0 }
  // CHECK-NEXT: iassign <* i32> 0 (dread a64 %z, dread i32 %_result[[#RES6]])
  *z = ibaz(z, x);
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: icallassigned (dread a64 %ibaz, dread a64 %z, dread i32 %y) { dassign %_result[[#RES7:]] 0 }
  // CHECK-NEXT: eval (add i32 (dread i32 %x, dread i32 %_result[[#RES7]]))
  x + ibaz(z, y);
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: icallassigned (dread a64 %ibaz, dread a64 %z, dread i32 %y) { dassign %_result[[#RES8:]] 0 }
  // CHECK-NEXT: dassign $gA1 2 (dread i32 %_result[[#RES8]])
  gA1.y = ibaz(z, y);
}

void declStmt(int (ifoo)(int), int x, int *y) {
  // CHECK: LOC 2 [[#LINEA: @LINE + 3 ]]{{$}}
  // CHECK-NEXT: var %a i32
  // CHECK-NEXT: var %_result[[#]] i32
  int a = baz(y, x);
  // CHECK: LOC 2 [[#LINEB: @LINE + 3 ]]{{$}}
  // CHECK-NEXT: var %b i32
  // CHECK-NEXT: var %_result[[#]] i32
  int b = ifoo(x);

  // CHECK: LOC 2 [[#LINEA]]{{$}}
  // CHECK-NEXT: callassigned &baz (dread a64 %y, dread i32 %x) { dassign %_result[[#RES9:]] 0 }
  // CHECK-NEXT: dassign %a 0 (dread i32 %_result[[#RES9]])

  // CHECK: LOC 2 [[#LINEB]]{{$}}
  // CHECK-NEXT: icallassigned (dread a64 %ifoo, dread i32 %x) { dassign %_result[[#RES10:]] 0 }
  // CHECK-NEXT: dassign %b 0 (dread i32 %_result[[#RES10]])
}
